/**********************************************************************/
/*                                                                    */
/*           File bws2.c:  Multiprocessor Simulation Model 2          */
/*                                                                    */
/*  This is a synchronous model of a multiprocessor memory-bus sub-   */
/*  system with first-in, first out request queueing.  It is a revi-  */
/*  sion of model bws1;  the major changes are shown in Figure 5.7.   */
/*                                                                    */
/**********************************************************************/
/*  KJC (10/10/95) - Changed <> to "" on include statement            */
/**********************************************************************/
#include "smpl.h"

#define busy 1

real
  p=0.250,         /* local memory miss rate            */
  treq[17],        /* next request time for processor   */
  tn=1.0E6;        /* earliest-occurring request time   */
int
  N=8,M=4,nB=2,    /* no. processors, memories, & buses */
  module[17],bus,  /* memory & bus facility descriptors */
  nbs=0,           /* no. busy buses in current cycle   */
  req[17],         /* currently-requested memory module */
  next=1;          /* arbitration scan starting point   */

/*-------------------  MEMORY-BUS BANDWIDTH MODEL  -------------------*/
main()
  {
    int event,i,n;
    smpl(0,"Bandwidth Model");
    bus=facility("bus",nB);
    for (i=1; i<=M; i++) module[i]=facility("module",1);
    for (n=1; n<=N; n++) {req[n]=0; next_access(n);}
    schedule(1,tn,0);
    while (time()<10000.0)
      {
        cause(&event,&n);
        switch(event)
          {
            case 1:  begin_cycle(); break;
            case 2:  req_module(n); break;
            case 3:  req_bus(n);    break;
            case 4:  end_cycle(n);  break;
          }
      }
    printf("bw = %.3f\n",U(bus));
  }

/*--------------------  COMPUTE NEXT ACCESS TIME  -------------------*/
next_access(n)
  int n;
    {
      real t;
      t=floor(log(ranf())/log(1.0-p))+time();
      treq[n]=t; if (t<tn) then tn=t;
    }

/*----------------------  EVENT 1:  BEGIN CYCLE  ---------------------*/
begin_cycle()
  {
    int i,n=next; real t,tmin=1.0E6;
    for (i=0; i<N; i++)
      {
        if (!req[n]) then
          {
            if ((t=treq[n])==tn)
              then
                {req[n]=random(1,M); schedule(2,0.0,n);}
              else if (t<tmin) then tmin=t;
          }
        n=(n%N)+1;
      }
    next=(next%N)+1; tn=tmin;
  }

/*--------------------  EVENT 2:  REQUEST MEMORY  --------------------*/
req_module(n)
  int n;
    {
      if (request(module[req[n]],n,0)==0) then
        schedule(3,0.0,n);
    }

/*---------------------  EVENT 3:  REQUEST BUS  ----------------------*/
req_bus(n)
  int n;
    {
      if (request(bus,n,0)==0) then
        {nbs++; schedule(4,1.0,n);}
    }

/*-----------------------  EVENT 4:  END CYCLE  ----------------------*/
end_cycle(n)
  int n;
    {
      req[n]=-req[n]; nbs--;
      if (nbs==0) then
        {
          for (n=1; n<=N; n++)
            if (req[n]<0) then
              {
                release(bus,n);
                release(module[-req[n]],n);
                req[n]=0; next_access(n);
              }
          schedule(1,tn-time(),0);
        }
    }
